package dragon.core.runtime;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.junit.Test;

import dragon.core.db.ColumnMeta;
import dragon.core.db.DML;
import dragon.core.db.TableMeta;
import dragon.core.exception.ExceptionHandler;
import dragon.core.io.FileHandler;
import dragon.core.util.StringUtils;

public class GeneratorPo {

	String _n = "\n";

	String _t = "\t";

	String dot = ".";

	String semicolon = ";";

	/**
	 * 默认源文件目录
	 */
	private String defaultSourceFolder = "src";

	/**
	 * 默认class目录
	 */
	private String defaultOutputFolder = "bin";

	public void setDefaultOutputFolder(String defaultOutputFolder) {
		this.defaultOutputFolder = defaultOutputFolder;
	}

	public void setDefaultSourceFolder(String defaultSourceFolder) {
		this.defaultSourceFolder = defaultSourceFolder;
	}

	@Test
	public void test() {
		String packageName = "dragon.core.system.po";
		String schemaName = "sys";
		String tableName = "t_sys_usermanagementroles";
		String[] pks = new String[] { "usergroupid", "userid" };
		GeneratorPo generateor = new GeneratorPo();
		try {
			generateor.generate(packageName, schemaName, tableName, pks);
		} catch (ExceptionHandler e) {
			e.printStackTrace();
		}

	}

	/**
	 * 根据指定的数据表生成PO类
	 * 
	 * @param packageName
	 * @param schemaname
	 * @param tableName
	 * @param pks
	 * @throws ExceptionHandler
	 */
	public void generate(String packageName, String schemaname, String tableName, String... pks) throws ExceptionHandler {

		if (StringUtils.isEmpty(tableName)) {
			return;
		}

		if (!StringUtils.isPackageNameCorrect(packageName)) {
			throw new ExceptionHandler("给定的包名不正确：" + packageName);
		}
		packageName = packageName.trim().toLowerCase();

		// 读取数据表字段元数据
		TableMeta table = DML.getTableMeta(schemaname, tableName, pks);
		if (table == null) {
			throw new ExceptionHandler("数据表或视图：" + tableName + " 不存在！");
		}
		table.setSchemaname(schemaname);
		table.setName(table.getName().toLowerCase());
		table.setClassName(table.getName());

		// 对table进行预处理
		List<TableMeta> list = pTable(table);
		for (TableMeta t : list) {
			outputClass(packageName, t);
		}

	}

	public List<TableMeta> pTable(TableMeta table) throws ExceptionHandler {

		List<TableMeta> list = new ArrayList<TableMeta>();
		list.add(table);
		boolean needTransform = false;

		ColumnMeta[] columns = table.getColumns();
		for (ColumnMeta col : columns) {
			if ("CLOB".equals(col.getColumnTypeName())) {
				needTransform = true;
				break;
			}
		}
		if (!needTransform) {
			return list;
		}

		// 进行置换
		TableMeta tableClone = null;
		try {
			tableClone = (TableMeta) table.clone();
		} catch (CloneNotSupportedException e) {
			throw new ExceptionHandler(e);
		}
		tableClone.setClassName(tableClone.getName() + "Clone");
		ColumnMeta[] columnsClone = tableClone.getColumns();
		for (int i = 0; i < columns.length; i++) {
			ColumnMeta col = columns[i];
			ColumnMeta colClone = columnsClone[i];

			// 特殊类型转换
			if ("CLOB".equals(col.getColumnTypeName())) {
				col.setColumnClassName("java.sql.Clob");

				colClone.setColumnClassName("java.lang.String");
			}
		}
		list.add(tableClone);

		return list;
	}

	@SuppressWarnings("rawtypes")
	private void outputClass(String packageName, TableMeta table) throws ExceptionHandler {

		ColumnMeta[] cols = table.getColumns();

		StringBuilder cs = new StringBuilder();
		// package
		if (!"".equals(packageName)) {
			cs.append("package ").append(packageName).append(semicolon).append(_n).append(_n);
		}

		// import域
		Map<String, String> imports = new HashMap<String, String>();
		if (cols != null) {
			for (ColumnMeta col : cols) {
				String columnClassName = col.getColumnClassName();

				if (!columnClassName.startsWith("java.lang.") && !imports.containsKey(columnClassName)) {
					cs.append("import ").append(columnClassName).append(semicolon).append(_n);
					imports.put(columnClassName.toString(), null);
				}
			}
		}
		if (imports.size() > 0) {
			cs.append(_n);
		}

		// 添加class头部
		cs.append("/**").append(_n);
		cs.append(" * ").append(table.getComment()).append(_n);
		cs.append(" */").append(_n);
		String className = StringUtils.table2Class(table.getClassName());
		cs.append("public class ").append(className).append(" {").append(_n);

		// 添加数据表名
		cs.append(_n);
		cs.append(_t).append("/**").append(_n);
		cs.append(_t).append(" * ").append("数据表名").append(_n);
		cs.append(_t).append(" */").append(_n);
		cs.append(_t).append("public static String tableName = \"").append(table.toString()).append("\"").append(semicolon).append(_n);
		cs.append(_n);

		// 添加属性
		Map<String, String> column2Field = new HashMap<String, String>();// 暂存属性到字段的映射关系
		if (cols != null) {
			for (ColumnMeta col : cols) {
				String columnClassName = col.getColumnClassName();
				columnClassName = columnClassName.substring(columnClassName.lastIndexOf(dot) + 1);
				if ("Integer".equals(columnClassName)) {
					columnClassName = "int";
				}
				String fieldName = StringUtils.column2Field(col.getColumnName().toLowerCase());
				if (!fieldName.equalsIgnoreCase(col.getColumnName())) {
					column2Field.put(fieldName, col.getColumnName());
				}
				// 属性注释
				cs.append(_t).append("/**").append(_n);
				cs.append(_t).append(" * ").append(col.getComment()).append(_n);
				cs.append(_t).append(" */").append(_n);

				// 属性
				cs.append(_t).append("private ").append(columnClassName).append(" ").append(fieldName).append(semicolon).append(_n).append(_n);

				// 特殊类型附加
				if ("Clob".equals(columnClassName)) {
					// 属性注释
					cs.append(_t).append("/**").append(_n);
					cs.append(_t).append(" * ").append(col.getComment()).append("(String)").append(_n);
					cs.append(_t).append(" */").append(_n);

					// 属性
					cs.append(_t).append("private String ").append(fieldName).append("Str").append(semicolon).append(_n).append(_n);
				}
			}
		}

		// 默认的toString 方法
		cs.append(_t).append("@Override").append(_n);
		cs.append(_t).append("public String toString() {").append(_n);
		cs.append(_t).append(_t).append("StringBuilder str = new StringBuilder();").append(_n);
		if (cols != null) {
			for (ColumnMeta col : cols) {
				String fieldName = StringUtils.column2Field(col.getColumnName().toLowerCase());
				cs.append(_t).append(_t).append("str.append(\"").append(fieldName).append("=\").append(").append(fieldName).append(").append(\"\\t\");").append(_n);
				// 特殊类型附加
				if ("java.sql.Clob".equals(col.getColumnClassName())) {
					cs.append(_t).append(_t).append("str.append(\"").append(fieldName).append("Str=\").append(").append(fieldName).append("Str).append(\"\\t\");").append(_n);
				}
			}
		}
		cs.append(_t).append(_t).append("return str.toString();").append(_n);
		cs.append(_t).append("}").append(_n).append(_n);

		// 设置getter和setter
		if (cols != null) {
			for (ColumnMeta col : cols) {
				String columnClassName = col.getColumnClassName();
				columnClassName = columnClassName.substring(columnClassName.lastIndexOf(dot) + 1);
				if ("Integer".equals(columnClassName)) {
					columnClassName = "int";
				}

				String fieldName = StringUtils.column2Field(col.getColumnName().toLowerCase());
				String methodSuffix = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);// 首字母大写

				// set
				cs.append(_t).append("public void set").append(methodSuffix).append("(").append(columnClassName).append(" ").append(fieldName).append(") {").append(_n);
				cs.append(_t).append(_t).append("this.").append(fieldName).append(" = ").append(fieldName).append(semicolon).append(_n);
				cs.append(_t).append("}").append(_n).append(_n);

				// get
				cs.append(_t).append("public ").append(columnClassName).append(" get").append(methodSuffix).append("() {").append(_n);
				cs.append(_t).append(_t).append("return this.").append(fieldName).append(semicolon).append(_n);
				cs.append(_t).append("}").append(_n).append(_n);

				// 特殊类型附加
				if ("Clob".equals(columnClassName)) {
					// set
					cs.append(_t).append("public void set").append(methodSuffix).append("(String ").append(fieldName).append("Str) {").append(_n);
					cs.append(_t).append(_t).append("this.").append(fieldName).append("Str = ").append(fieldName).append("Str").append(semicolon).append(_n);
					cs.append(_t).append("}").append(_n).append(_n);

					// get
					cs.append(_t).append("public String get").append(methodSuffix).append("Str() {").append(_n);
					cs.append(_t).append(_t).append("return this.").append(fieldName).append("Str").append(semicolon).append(_n);
					cs.append(_t).append("}").append(_n).append(_n);
				}
			}
		}

		// 添加class尾部
		cs.append("}");

		// 输出到文件
		String filePath = FileHandler.getClassRootPath();
		filePath = filePath.replace(defaultOutputFolder, defaultSourceFolder);

		String path = "";
		if (!"".equals(packageName)) {
			path = packageName;
			path = path.replaceAll("\\.", "/");
			if (!path.endsWith("/")) {
				path += "/";
			}
		}
		filePath = filePath + path + className + ".java";

		FileHandler.createPlainTextFile(filePath, cs.toString(), null);

		// 生成映射信息
		if (!className.equalsIgnoreCase(table.getName()) || column2Field.size() > 0) {
			StringBuilder mapping = new StringBuilder("<tableMapping class=\"").append(packageName).append(".").append(className).append("\" table=\"").append(table.getName())
					.append("\" reloadAfterSave=\"false\"");

			// 字段映射
			if (column2Field.size() > 0) {
				mapping.append(">");

				Set set = column2Field.keySet();
				Iterator it = set.iterator();
				while (it.hasNext()) {
					String fieldName = (String) it.next();
					String columnName = column2Field.get(fieldName);
					mapping.append("\n\t").append("<columnMapping property=\"").append(fieldName).append("\" column=\"").append(columnName).append("\"/>");
				}
				mapping.append("\n");

				mapping.append("</tableMapping>");
			} else {
				mapping.append("/>");
			}

			System.out.println("需要更新配置文件：\n" + mapping);
		}
	}
}
